﻿#include "FITKSEASubSysAbsShell.h"
#include "FITKAbstractSEAFace.h"
#include "FITKAcousticsDiscNodeList.h"
#include "FITKAcousticsSEAModel.h"
#include "FITKAcousticsDiscModel.h"
#include "FITKSEASubSysModelProp.h"
#include "FITKAcousticsTriangles.h"
#include "FITK_Interface/FITKInterfaceModel/FITKAbstractElement.h"
#include "FITK_Interface/FITKInterfaceModel/FITKElementList.h"
#include "FITK_Interface/FITKInterfaceModel/FITKCoordinateSystem.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsAbstractSpectra.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsAbsNCT.h"
#include "FITK_Kernel/FITKCore/FITKDataRepo.h"
#include "FITK_Kernel/FITKCore/FITKVec3DAlg.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"

#include "FITKAcousticsFEModel.h"
#include "FITKAcousticsFENodeMap.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaMeshPartVTK.h"
#include "FITK_Component/FITKAbaqusData/FITKAbaqusPart.h"
#include "FITK_Interface/FITKInterfaceModel/FITKElementFactory.h"
#include "FITK_Component/FITK2DMeshTools/FITKAbstractSeparatePlate.h"
#include "FITK_Interface/FITKInterfaceModel/FITKElementTri.h"

namespace Acoustics
{
    FITKAbstractSEASubSysShell::FITKAbstractSEASubSysShell()
        :FITKAbstractSEASubSysWithNodes()
    {
        
    }
 

    FITKAbstractSEASubSysShell::~FITKAbstractSEASubSysShell()
    {
   
    }

    FITKAcousticsTriangles* FITKAbstractSEASubSysShell::getTriangleMesh()
    {
        FITKAbstractSEAFace* face = this->getFaceObj();
        if (face) return face->getTriangleMesh();
        return nullptr;
    }

    QList<int> FITKAbstractSEASubSysShell::getTriangleNodeIDs()
    {
        FITKAcousticsTriangles* t = this->getTriangleMesh();
        if (t == nullptr) return QList<int>();
        return t->getAllNodeIDs();
    }

    int FITKAbstractSEASubSysShell::getFlexureSpectraID()
    {
        return _flexureSpectraID;
    }

    FITKAcousticsAbstractSpectra * FITKAbstractSEASubSysShell::getFlexureSpectra()
    {
        return FITKDATAREPO->getTDataByID<FITKAcousticsAbstractSpectra>(_flexureSpectraID);
    }

    void FITKAbstractSEASubSysShell::setFlexureSpectraID(int id)
    {
        _flexureSpectraID = id;
    }

    int FITKAbstractSEASubSysShell::getExtensionSpectraID()
    {
        return _extensionSpectraID;
    }

    FITKAcousticsAbstractSpectra * FITKAbstractSEASubSysShell::getExtensionSpectra()
    {
        return FITKDATAREPO->getTDataByID<FITKAcousticsAbstractSpectra>(_extensionSpectraID);
    }

    void FITKAbstractSEASubSysShell::setExtensionSpectraID(int id)
    {
        _extensionSpectraID = id;
    }

    int FITKAbstractSEASubSysShell::getShearSpectraID()
    {
        return _shearSpectraID;
    }

    FITKAcousticsAbstractSpectra * FITKAbstractSEASubSysShell::getShearSpectra()
    {
        return FITKDATAREPO->getTDataByID<FITKAcousticsAbstractSpectra>(_shearSpectraID);
    }

    void FITKAbstractSEASubSysShell::setShearSpectraID(int id)
    {
        _shearSpectraID = id;
    }

    bool FITKAbstractSEASubSysShell::updateTriMesh()
    {
        //纯虚函数用于更新三角网格-子类中实现
        return false;
    }

    bool FITKAbstractSEASubSysShell::updateTriMesh(QHash<int, QList<int>> faceMeshData)
    {
        //获取离散数据
        Acoustics::FITKAcousticsDiscModel* discModel = FITKAPP->getGlobalData()->getMeshData<Acoustics::FITKAcousticsDiscModel>();
        if (!discModel)return false;
        //获取SEA模型和FE模型
        Acoustics::FITKAcousticsSEAModel* seaModel = discModel->getSEAModel();
        Acoustics::FITKAcousticsFEModel* feModel = discModel->getFEModel();
        FITKAcousticsDiscNodeList* nodeListDisc = discModel->getNodes();
        FITKSEAFaceManager* seaFaceMgr = seaModel->getSEAFaceManager();
        if (!feModel || !seaModel || !nodeListDisc || !seaFaceMgr)return false;
        //获取FE模型的映射表
        FITKAcousticsFENodeMapManager* feNodeMapMgr = feModel->getNodesMapManager();
        if (!feNodeMapMgr)return false;
        //创建SEA面数据
        FITKAbstractSEAFace* face = FITKSEAFaceManager::CreateSEAFace(this->getSEASubSysType());
        if (!face) return false;
        //设置面数据
        this->setFaceID(face->getDataObjectID());
        seaFaceMgr->appendDataObj(face);
        //获取网格数据
        FITKAcousticsTriangles* triMesh = this->getTriangleMesh();
        if (!triMesh)return false;
        //单元链表
        QList<Interface::FITKAbstractElement*> elementList;
        for (QHash<int, QList<int>>::iterator iter = faceMeshData.begin(); iter != faceMeshData.end(); ++iter)
        {
            int partID = iter.key();
            QList<int> elemIDList = iter.value();
            if (elemIDList.isEmpty())continue;
            //获取部件和网格信息
            AbaqusData::FITKAbaqusPart* partData = FITKDATAREPO->getTDataByID<AbaqusData::FITKAbaqusPart>(partID);
            if (!partData)continue;
            Interface::FITKAbaMeshPartVTK* mesh = partData->getMesh();
            if (!mesh)continue;
            //获取FE模型映射表
            FITKAcousticsFENodeMap* feNodeMap = feNodeMapMgr->getFENodeMapByPartID(partID);
            if (!feNodeMap) continue;
            for (int elemID : elemIDList)
            {
                Interface::FITKAbstractElement* elemData = mesh->getElementByID(elemID);
                if (!elemData)continue;
                //获取点
                QList<int> nodeIDList;
                int nodeCount = elemData->getNodeCount();
                for (int i = 0; i < nodeCount; ++i)
                {
                    int nodeID = elemData->getNodeID(i);
                    int nodeIDSEA = feNodeMap->getDiscNodeID(nodeID);
                    nodeIDList.append(nodeIDSEA);
                }
                if (elemData->getEleType() == Interface::FITKModelEnum::FITKEleType::Tri3 && nodeCount == 3)
                {
                    Interface::FITKAbstractElement* element = Interface::FITKElementFactory::createElement(Interface::FITKModelEnum::FITKEleType::Tri3);
                    element->setNodeID(QList<int>() << nodeIDList.at(0) << nodeIDList.at(1) << nodeIDList.at(2));
                    elementList.append(element);
                    triMesh->appendElement(element);
                }
                else if (elemData->getEleType() == Interface::FITKModelEnum::FITKEleType::Quad4 && nodeCount == 4)
                {
                    Interface::FITKAbstractElement* element = Interface::FITKElementFactory::createElement(Interface::FITKModelEnum::FITKEleType::Tri3);
                    element->setNodeID(QList<int>() << nodeIDList.at(0) << nodeIDList.at(1) << nodeIDList.at(3));
                    elementList.append(element);
                    triMesh->appendElement(element);
                    element = Interface::FITKElementFactory::createElement(Interface::FITKModelEnum::FITKEleType::Tri3);
                    element->setNodeID(QList<int>() << nodeIDList.at(1) << nodeIDList.at(2) << nodeIDList.at(3));
                    elementList.append(element);
                    triMesh->appendElement(element);
                }
            }
        }
        if (elementList.isEmpty()) return false;
        //获取节点数据
        QList<int> nodeIDs = triMesh->getAllNodeIDs();
        QList< Core::FITKNode*> nodeList;
        for (int nID : nodeIDs)
        {
            Core::FITKNode* nodeData = nodeListDisc->getNodeByID(nID);
            if (!nodeData) continue;
            nodeList.append(nodeData);
        }
        //创建分离板件工具
        Interface::FITKAbstractSeparatePlate* separatePlateTool = Interface::FITKAbstractSeparatePlate::createFITKSeparatePlate();
        if (!separatePlateTool) return false;
        //查看连续性
        QList<QList<int>> plateElemIndexs = separatePlateTool->getPlates(nodeList, elementList);
        //销毁分离板件工具
        delete separatePlateTool;
        separatePlateTool = nullptr;
        if (plateElemIndexs.size() != 1) return false;
        //更新模型属性
        face->updateModelProp();
        FITKSEASubSysModelProp* modelProp = face->getModelPorp();
        //更新边界节点数据
        QList<QPair<int, int>> boundNodeID = modelProp->getBoundary();
        if (boundNodeID.isEmpty()) return false;
        QList<int> nodeIDListSEA;
        nodeIDListSEA.append(boundNodeID.at(0).first);
        int count = boundNodeID.size();
        for (int i = 0; i < count; ++i)
        {
            int flatID = nodeIDListSEA.last();
            for (int j = 0; j < boundNodeID.size(); ++j)
            {
                if (boundNodeID.at(j).first != flatID || nodeIDListSEA.contains(boundNodeID.at(j).second)) continue;
                nodeIDListSEA.append(boundNodeID.at(j).second);
                boundNodeID.removeAt(j);
                break;
            }
        }
        QList<SubSysNode> nodes;
        for (int i = 0; i < nodeIDListSEA.size(); ++i)
        {
            SubSysNode nodeData;
            nodeData._id = nodeIDListSEA.at(i);
            nodes.append(nodeData);
        }
        this->setNodes(nodes);
        return true;
    }

    void FITKAbstractSEASubSysShell::setFromUserSpectraState(bool state)
    {
        //设置是否使用来自用户光谱的开启状态-true：使用用户已选择的光谱 false：使用软件默认的光谱
        _fromUserSpectraState = state;
    }
    void FITKAbstractSEASubSysShell::setFromPhysicalPropState(bool state)
    {
        //设置是否使用来自物理属性的开启状态-true：使用物理属性 false：不使用物理属性
        _fromPhysicalPropState = state;
    }
    void FITKAbstractSEASubSysShell::setFromNoiseControlState(bool state)
    {
        //设置是否使用来自噪声控制的开启状态-true：使用噪声控制 false：不使用噪声控制
        _fromNoiseControlState = state;
    }

    bool FITKAbstractSEASubSysShell::getFromUserSpectraState()
    {
        //获取来自用户光谱开启状态
        return _fromUserSpectraState;
    }
    bool FITKAbstractSEASubSysShell::getFromPhysicalPropState()
    {
        //获取来自物理属性开启状态
        return _fromPhysicalPropState;
    }
    bool FITKAbstractSEASubSysShell::getFromNoiseControlState()
    {
        //获取来自噪声控制开启状态
        return _fromNoiseControlState;
    }
    void FITKAbstractSEASubSysShell::setOutsideNCTID(int id)
    {
        //设置外部声学包
        FITKAbstractSEAFace* faceData = this->getFaceObj();
        if (faceData)
            faceData->setOutsideNCTID(id);
    }

    int FITKAbstractSEASubSysShell::getOutsideNCTID()
    {
        //获取外部声学包id
        FITKAbstractSEAFace* faceData = this->getFaceObj();
        if (faceData)
            return faceData->getOutsideNCTID();
        return -1;
    }

    FITKAcousticsAbsNCT* FITKAbstractSEASubSysShell::getOutsideNCT()
    {
        //获取外部声学包
        FITKAbstractSEAFace* faceData = this->getFaceObj();
        if (faceData)
            return faceData->getOutsideNCT();
        return nullptr;
    }

    void FITKAbstractSEASubSysShell::setInsideNCTID(int id)
    {
        //设置内部声学包
        FITKAbstractSEAFace* faceData = this->getFaceObj();
        if (faceData)
            faceData->setInsideNCTID(id);
    }

    int FITKAbstractSEASubSysShell::getInsideNCTID()
    {
        //获取内部声学包id
        FITKAbstractSEAFace* faceData = this->getFaceObj();
        if (faceData)
            return faceData->getInsideNCTID();
        return -1;
    }

    FITKAcousticsAbsNCT* FITKAbstractSEASubSysShell::getInsideNCT()
    {
        //获取内部声学包
        FITKAbstractSEAFace* faceData = this->getFaceObj();
        if (faceData)
            return faceData->getInsideNCT();
        return nullptr;
    }

    void FITKAbstractSEASubSysShell::setOutsideNCTCoveredArea(double percentage)
    {
        //设置外部声学包覆盖率
        FITKAbstractSEAFace* faceData = this->getFaceObj();
        if (faceData)
            return faceData->setOutsideNCTCoveredArea(percentage);
    }

    double FITKAbstractSEASubSysShell::getOutsideNCTCoveredArea()
    {
        //获取外部声学包覆盖率
        FITKAbstractSEAFace* faceData = this->getFaceObj();
        if (faceData)
            return faceData->getOutsideNCTCoveredArea();
        return 0.0;
    }

    void FITKAbstractSEASubSysShell::setInsideNCTCoveredArea(double percentage)
    {
        //设置内部声学包覆盖率
        FITKAbstractSEAFace* faceData = this->getFaceObj();
        if (faceData)
            return faceData->setInsideNCTCoveredArea(percentage);
    }

    double FITKAbstractSEASubSysShell::getInsideNCTCoveredArea()
    {
        //获取内部声学包覆盖率
        FITKAbstractSEAFace* faceData = this->getFaceObj();
        if (faceData)
            return faceData->getInsideNCTCoveredArea();
        return 0.0;
    }

    bool FITKAbstractSEASubSysShell::updateCoordinate()
    {
        if (nullptr ==  _coordinate) return false;
        //子系统至少三个点
        QList<int> nodeIDs = this->getNodeIDs();
        if (nodeIDs.size() < 3) return false;
        //声学sea模型节点获取
        FITKAcousticsDiscNodeList* nodes = FITKAcousticsDiscModel::GetDiscModelFromFrame()->getNodes();
        if (nodes == nullptr) return false;

        double coor[3] = { 0,0,0 };
        //第一个点,坐标系原点
        Core::FITKNode* node0 =  nodes->getNodeByID(nodeIDs[0]);
        if (nullptr == node0) return false;
        node0->getCoor(coor);
        _coordinate->setOrigin(coor[0], coor[1], coor[2]);
        //第二点，x轴上的一点
        Core::FITKNode* node1 = nodes->getNodeByID(nodeIDs[1]);
        if (nullptr == node1) return false;
        node1->getCoor(coor);
        _coordinate->setPoint1(coor[0], coor[1], coor[2]);
        //x轴方向
        Core::FITKVec3D xDir = Core::Subtract(*node1, *node0);
        //计算三角形法向作为z轴
        FITKAcousticsTriangles* tris = this->getTriangleMesh();
        if (tris == nullptr) return false;
        QList<Interface::FITKAbstractElement*> eles = tris->getNeighborElement(nodeIDs[0]);
        if (eles.isEmpty()) return false;
        //找到一个三角形
        Interface::FITKAbstractElement* ele = eles.at(0);
        const int pid =  ele->getPreviousNodeID(nodeIDs[0]);
        const int nid = ele->getNextNodeID(nodeIDs[0]);
        //计算三角形法向
        Core::FITKNode* nodep = nodes->getNodeByID(pid);
        Core::FITKNode* noden = nodes->getNodeByID(nid);

        Core::FITKVec3D v1 = Core::Subtract(*nodep, *node0);
        Core::FITKVec3D v2 = Core::Subtract(*noden, *node0);
        //z轴方向
        Core::FITKVec3D normal = Core::CrossProduct(v2, v1);//顺序不能错
        //Y轴方向
        Core::FITKVec3D yDir = Core::CrossProduct(xDir, normal);//顺序不能错
        //坐标轴第二坐标轴上的一点
        _coordinate->setPoint2(node0->x() + yDir.x(), node0->y() + yDir.y(), node0->z() + yDir.z());
        return true;
    }
}


